#include "ProportionalEnv.hpp"

#include <algorithm>
#include <cstdio>
#include <ctime>

#include <iostream>

Gene identityScalingFunction(const Gene& value)
{
  return value;
}

class IdentityScalingFunction: public ScalingFunction
{
public:
  virtual Gene operator()(const Gene &value){return value;};
};


  ProportionalEnv::ProportionalEnv():_scalingFunction(NULL)
{
}

//void ProportionalEnv::setScalingFunction(Gene (*scalingFunction)(const Gene&))
void ProportionalEnv::setScalingFunction(ScalingFunction *scalingFunction)
{
  (*scalingFunction)(3);//i assume that if this does not rise an error, 
  //the function works
  _scalingFunction=scalingFunction;
}

void ProportionalEnv::selection()
{
  srand(time(NULL));
  _parents.clear();
  /*
  std::cerr<<"sel"<<std::endl;

  for(unsigned i=0;i<_children.size();++i)
    {
      for(unsigned j=0;j<_children[i].getDimensions();++j)
	{
	  std::cerr<<_children[i][j]<<" ";
	}
      std::cerr<<" fitness: "<<_children[i].getFitness()<<std::endl;
    }

  std::cerr<<""<<std::endl;
  */

  
  sort(_children.begin(),_children.end());
  std::vector<Gene> roulette;
  roulette.resize(_children.size());

  try{

    {
      Gene sum=0;
      Gene maximum=(std::max_element(_children.begin(),
				     _children.end()))->getFitness();		  
      std::vector<Gene> probability;
      probability.resize(_children.size());
 
      maximum+=0.1*abs(maximum);

      //		  std::cerr<<maximum<<std::endl;
      if(_scalingFunction)
	{

	  for(unsigned i=0;i<_children.size();++i)
	    {
	      probability[i]=maximum-_children[i].getFitness(); 
	      // all results are shifted to positive values and 
	      //altered, so the minimum has the highest probability
	      probability[i]=(*_scalingFunction)(probability[i]);
	      sum+=probability[i];
	    }
	}
      else
	{
	  for(unsigned i=0;i<_children.size();++i)
	    {
	      probability[i]=maximum-_children[i].getFitness(); 
	      // all results are shifted to positive values and 
	      //altered, so the minimum has the highest probability
	      sum+=probability[i];
	    }
	}
      for(unsigned i=0;i<_children.size();++i)
	{
	  probability[i]/=sum;
	  //		  std::cerr<<probability[i]<<std::endl;
	}
    
      //	  std::cerr<<std::endl;		  

      roulette[0]=probability[0];
      for(unsigned i=1;i<_children.size()-1;++i) //do poprawki
	{
	  roulette[i]=probability[i]+roulette[i-1];
	}
    }
    //  std::cerr<<RAND_MAX<<std::endl;
    for(unsigned i=0;i<_children.size();++i)
      {
	Gene hit=rand();
	//      std::cerr<<hit<<std::endl;
	hit/=RAND_MAX;
	//      std::cerr<<hit<<std::endl;
	unsigned j=0;
	while(j<_children.size() && hit>roulette[j] )
	  {
	    ++j;
	  }
		
		
	if(j>=_children.size())
	  {
	    --i;
	    continue;
	  }
	//		std::cerr<<"j "<<j<<" roulette "<<roulette[j]<<std::endl;
	/*
	  for(unsigned k=0;k<_children[j].getDimensions();++k)
	  {
	  std::cerr<<_children[j][k]<<" ";
	  }
	  std::cerr<<std::endl;
	*/
	_parents.push_back(_children[j]);
		
      }
  }
  catch(std::exception &ex)
    {
      throw ex;
    }
  //  std::cerr<<"finished"<<std::endl;
}
/*
std::cerr<<std::endl;

    for(unsigned i=0;i<_parents.size();++i)
    {
      for(unsigned j=0;j<_parents[i].getDimensions();++j)
	{
	  std::cerr<<_parents[i][j]<<" ";
	}
      std::cerr<<" fitness: "<<_parents[i].getFitness()<<std::endl;
    }

  std::cerr<<""<<std::endl;
  */


ProportionalEnv::~ProportionalEnv()
{
  if(_scalingFunction)
    delete _scalingFunction;
}
